//
// Created by xkj on 2020/10/27.
//

#ifndef PROJ_ANDROID_SOCKETIOHELPER_H
#define PROJ_ANDROID_SOCKETIOHELPER_H

#include "base/CCScheduler.h"
#include "extensions/cocos-ext.h"
#include "network/SocketIO.h"

USING_NS_CC;
USING_NS_CC_EXT;
using namespace cocos2d::network;
using namespace std;

typedef enum {
    DISCONNECT,
    CONNECTING,
    CONNECTED
} CONNECT_STATUS;

class SocketIOHelperDelegate
{
public:
    virtual void SioConnection(SIOClient *, const std::string&) = 0;
    virtual void SioOnline(SIOClient *, const std::string&) = 0;
    virtual void SioStatInfo(SIOClient *, const std::string&) = 0;
    virtual void SioStoreRoomid(SIOClient *, const std::string&) = 0;
    virtual void SioShareCode(SIOClient *, const std::string&) = 0;
    virtual void SioOffline(SIOClient *, const std::string&) = 0;
    virtual void SioTalking(SIOClient *,const std::string &) = 0;
    virtual void SioRoomCommentator(SIOClient *, const std::string& ) = 0;
    virtual void SioOnConnect(SIOClient* ) = 0;
    virtual void SioOnMessage(SIOClient* , const std::string& ) = 0;
    virtual void SioOnError(cocos2d::network::SIOClient* , const std::string& ) = 0;
    virtual void SioOnClose(cocos2d::network::SIOClient* ) = 0;
    virtual void SioRoomVisitors(SIOClient *, const std::string& ) = 0;
};

class SocketIOHelper: public cocos2d::network::SocketIO::SIODelegate
{
public:
    static SocketIOHelperDelegate *delegate;
    static SocketIOHelper *singleton;

    static SocketIOHelper* getInstant(){
        if(singleton == nullptr){
            singleton = new SocketIOHelper();
        }

        return singleton;
    }


    static void checkConnection(bool isForceInit=false){
        if(singleton == nullptr){
            singleton = new SocketIOHelper();
        }else{
            if(singleton->isDisconnect()
            ){
                singleton->initSocket();
            }else {
                singleton->semiSioConnection();
            }
        }
    }
    bool isConnecting()
    {
        return connectState == CONNECTING;
    }
    bool isDisconnect()
    {
        return connectState == DISCONNECT;
    }
    bool isConnect()
    {
        return connectState == CONNECTED;
    }
    void semiSioConnection()
    {
        std::string connectionFlag = "b";
        SioConnectionImpl(sioClient, connectionFlag);
    }

    void emit(const std::string& eventname, const std::string& args)
    {
        sioClient->emit(eventname, args);
    }

    void disconnectImpl()
    {
        sioClient->disconnect();
        sioClient = nullptr;
    }

    ~SocketIOHelper()
    {
        delete singleton;
    }

    SocketIOHelper(){
        initSocket();
    }

    void initSocket()
    {
        connectState = CONNECTING;
        sioClient = nullptr;
        //return;
        //create a client by using this static method, url does not need to contain the protocol
        sioClient = SocketIO::connect("https://wx.ndmooc.com/", *this, "cacert.pem");
        //you may set a tag for the client for reference in callbacks
        sioClient->setTag("sioClient");
        //register event callbacks using the CC_CALLBACK_2() macro and passing the instance of the target class
        sioClient->on("connection", CC_CALLBACK_2(SocketIOHelper::SioConnectionImpl, this));
        sioClient->on("someone-online", CC_CALLBACK_2(SocketIOHelper::SioOnlineImpl, this));
        sioClient->on("stat-info", CC_CALLBACK_2(SocketIOHelper::SioStatInfoImpl, this));
        sioClient->on("store-roomid", CC_CALLBACK_2(SocketIOHelper::SioStoreRoomidImpl, this));
        sioClient->on("share-code", CC_CALLBACK_2(SocketIOHelper::SioShareCodeImpl, this));
        sioClient->on("someone-offline", CC_CALLBACK_2(SocketIOHelper::SioOfflineImpl, this));
        sioClient->on("someone-talking", CC_CALLBACK_2(SocketIOHelper::SioTalkingImpl, this));
        sioClient->on("room-commentators",CC_CALLBACK_2(SocketIOHelper::SioRoomCommentatorImpl, this));
        sioClient->on("room-visitors", CC_CALLBACK_2(SocketIOHelper::SioRoomVisitorsImpl, this));
    }

    //test event callback handlers, these will be registered with socket.io
    void SioConnectionImpl(SIOClient *client, const std::string& data) {
        connectState = CONNECTED;
        if(delegate != nullptr){
            delegate->SioConnection(client, data);
        }
    }
    void SioOnlineImpl(SIOClient *client, const std::string& data) {
        if(delegate != nullptr){
            delegate->SioOnline(client, data);
        }
    };
    void SioStatInfoImpl(SIOClient *client, const std::string& data) {
        if(delegate != nullptr){
            delegate->SioStatInfo(client, data);
        }
    }
    void SioStoreRoomidImpl(SIOClient *client, const std::string& md5) {
        if(delegate != nullptr){
            delegate->SioStoreRoomid(client, md5);
        }
    }
    void SioShareCodeImpl(SIOClient *client, const std::string& url) {
        if(delegate != nullptr) {
            delegate->SioShareCode(client, url);
        }
    }
    void SioOfflineImpl(SIOClient *client, const std::string& msg) {
        if(delegate != nullptr) {
            delegate->SioOffline(client, msg);
        }
    }
    void SioTalkingImpl(SIOClient *client, const std::string& msg) {
        if(delegate != nullptr) {
            delegate->SioTalking(client, msg);
        }
    }
    void SioRoomCommentatorImpl(SIOClient *client, const std::string& msg) {
        if(delegate != nullptr) {
            delegate->SioRoomCommentator(client, msg);
        }
    }
    void SioRoomVisitorsImpl(SIOClient *client, const std::string& msg) {
        if(delegate != nullptr) {
            delegate->SioRoomVisitors(client, msg);
        }
    }

    virtual void onConnect(SIOClient* client) override{
        connectState = CONNECTED;
        if(delegate != nullptr) {
            delegate->SioOnConnect(client);
        }
    };
    virtual void onMessage(SIOClient* client, const std::string& data) override{
        if(delegate != nullptr) {
            delegate->SioOnMessage(client,data);
        }
    };
    virtual void onError(cocos2d::network::SIOClient* client, const std::string& data)override
    {
        connectState = DISCONNECT;
        if(delegate != nullptr) {
            delegate->SioOnError(client,data);
        }
        //initSocket();
    };
    virtual void onClose(cocos2d::network::SIOClient* client)override
    {
        connectState = DISCONNECT;
        if(delegate != nullptr) {
            delegate->SioOnClose(client);
        }
        //initSocket();
    };
private:
    /*SIO 相关*/
    cocos2d::network::SIOClient *sioClient;
    CONNECT_STATUS connectState ;//
};

#endif //PROJ_ANDROID_SOCKETIOHELPER_H
